package com.chang.aop;

import com.chang.anno.RedisLimitAnnotation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;

/**
 * @author: changzhenxi
 * @date: 2025/08/12 20:59
 * @description:
 */
@Slf4j
@Aspect
@Component
public class RedisLimitAop {
    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final DefaultRedisScript<Long> RATE_LIMITER_SCRIPT;

    // 读取本地脚本
    static {
        RATE_LIMITER_SCRIPT = new DefaultRedisScript<>();
        // 加载Lua脚本（放在resources/scripts下）
        RATE_LIMITER_SCRIPT.setLocation(new ClassPathResource("scripts/rateLimiter.lua"));
        RATE_LIMITER_SCRIPT.setResultType(Long.class);
    }

    @Around("@annotation(com.chang.anno.RedisLimitAnnotation)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        log.info("环绕通知开始~~~~~~~");

        // 通过注解过去方法名
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        RedisLimitAnnotation annotation = method.getAnnotation(RedisLimitAnnotation.class);
        String key = annotation.key();
        String methodName = method.getName();

        String LimitRedisKey = key+"\t"+methodName;

        long limit = annotation.limit();
        int expire = annotation.expire();
        List<String> list = Collections.singletonList(key);
        // 3. 执行Lua脚本 (保证原子性)
        Long count = redisTemplate.execute(
                RATE_LIMITER_SCRIPT,
                list,
                String.valueOf(limit),
                String.valueOf(expire)
        );
        // 4. 处理限流结果
        if (count != null && count == 0) {
            log.info("启动限流功能key:"+LimitRedisKey);
            return annotation.msg();
        }
        Object result = point.proceed();
        log.info("环绕通知结束~~~~~~~");
        return result;
    }

}
